package com.bite.common.security.service;

import cn.hutool.core.lang.UUID;
import com.bite.common.core.constants.CacheConstants;
import com.bite.common.core.constants.JwtConstants;
import com.bite.common.core.domain.R;
import com.bite.common.core.enums.UserIdentity;
import com.bite.common.redis.service.RedisService;
import com.bite.common.core.domain.LoginUser;
import com.bite.common.core.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

//创建用户令牌
@Service
@Slf4j
public class TokenService {
    @Autowired
    private RedisService redisService;


    //生成token
    public String createToken(Long userId,String secret,Integer identity,String nickName){
        //生成jwt
        String userKey = UUID.fastUUID().toString();
        Map<String,Object> claims = new HashMap<>();
        claims.put(JwtConstants.LOGIN_USER_ID,userId);
        claims.put(JwtConstants.LOGIN_USER_KEY,userKey);
        String jwt = JwtUtils.createToken(claims, secret);
        //将jwt存入redis,过期时间，数据结构（字符串，列表，哈希表，集合，有序集合）
        //redis中 identity 1表示普通用户 2表示管理员  存储为对象，日后好扩展
        //通过判断redis中是否存在对应令牌来判断是否过期
        String key  = getTokenKey(userKey);
        LoginUser loginUser = new LoginUser();
        loginUser.setIdentity(identity);
        loginUser.setNickName(nickName);
        redisService.setCacheObject(key ,loginUser,CacheConstants.EXP, TimeUnit.MINUTES);//根据用户实际状态来设计，暂定为12h
        return jwt;
    }

    //身份验证通过之后进行延长
    //并且需要在用户请求到达controller之前就需要延长，因为controller应该专注于请求，并且有可能，请求达到controller已经开始执行时，正好过期而还没有及时延长时间
    //放到拦截器
    /**为什么token延长不放在过滤器中而放在拦截器中
     过滤器的职责是过滤不符合要求的请求，比如身份认证，安全之类的，但是token延长并不属于过滤不符合要求的请求，而且还需要放到controller层之前所以放到
     拦截器中，此时过滤器把不符合要求的请求都过滤之后在对请求进行修改就可以了
     拦截器在所有的过滤器之后执行  过滤器---servlet---拦截器，过滤器是在网关上，通过网关之后就开始路由，相当于在转发到controller时先经过绑定的拦截器
     ***/
    public void extendToken(String token,String secret){

        String userKey = getUserKey(token,secret);
        if(userKey == null) return;
        String key = getTokenKey(userKey);
        //做一个判断，如果过期剩余时间较短则延长
        //剩余三个小时的则延长
        //先查看当前的时间
        Long expire = redisService.getExpire(key);
        if(expire != null && expire < CacheConstants.REFRESH_TIME){
            //延长即重新设置延长时间
            redisService.expire(key,CacheConstants.EXP,TimeUnit.MINUTES);
        }

    }
    private String getTokenKey(String userKey){
        return CacheConstants.LOGIN_TOKEN_KEY + userKey;
    }
    //解析token
    private String getUserKey(String token,String secret) {
        //解析token
        Claims claims;
        try{
            claims =  JwtUtils.parseToken(token,secret);
            if(claims == null){
                return null;
            }
        }catch (Exception e){
            log.error("token : {} ,解析token出现异常",token,e);
            return null;
        }
        return JwtUtils.getUserKey(claims);
    }
    public Long getUserId(String token,String secret) {
        //解析token
        Claims claims;
        try{
            claims =  JwtUtils.parseToken(token,secret);
            if(claims == null){
                return null;
            }
        }catch (Exception e){
            log.error("token : {} ,解析token出现异常",token,e);
            return null;
        }
        return Long.valueOf(JwtUtils.getUserId(claims));
    }

    public LoginUser getLoginUser(String token,String secret) {

        String userKey = getUserKey(token,secret);
        if(userKey == null) {
            return null;
        }
       return  redisService.getCacheObject(getTokenKey(userKey),LoginUser.class);
    }
    public Boolean deleteLoginUser(String token, String secret) {
        String userKey = getUserKey(token,secret);
        if(userKey == null) {
            return false;
        }
       return redisService.deleteObject(getTokenKey(userKey));
    }


    public void refreshLoginUser(String nickName, String headImage, String s) {
    }
}
